package iotdbdemo

import (
	"container/list"
	"encoding/json"
	"fmt"
	"github.com/apache/iotdb-client-go/client"
	"github.com/apache/iotdb-client-go/rpc"
	"log"
	"math/rand"
	"strconv"
	"time"
)

// TerminalData root.vadm.dps.terminal_sn_2799
type TerminalData struct {

	//终端唯一编号
	TerminalSn string
	//终端是否定位，0：未定位，1：已定位
	IsFixed string
	//终端上报经度，以度为单位的纬度值乘以 10 的 6 次方，精确到百万分之一度
	Longitude string
	//终端上报纬度，以度为单位的纬度值乘以 10 的 6 次方，精确到百万分之一度
	Latitude string
	//终端上报海拔，米
	Elevation string
	//终端上报方向 1°
	Direction string
	//终端上报时间,UTC方式，秒
	TerminalTime string
	//终端上报里程, 0.1km
	TerminalMiles string

	//终端上报速度，1km/h
	Speed string

	//超速警告，0：无超速，1：超速
	TerminalOverSpeed string

	//GNSS模块状态，0：无疲劳驾驶，1：疲劳驾驶
	TerminalTiredDrive string

	//GNSS模块状态，0：无异常，1：GNSS模块异常
	TerminalGnssError string

	//GNSS天线开路状态，0：无异常，1：天线短路
	TerminalAntOpen string

	//GNSS天线短路状态，0：无异常，1：天线开路
	TerminalAntShort string

	//终端欠压状态，0：无异常，1：终端欠压
	TerminalUnderVol string

	//终端掉电状态，0：无异常，1：终端掉电
	TerminalNoVol string

	//终端ACC状态，0：未激活，1：已激活
	TerminalAccStatus string

	//无线网络信号强度
	TerminalNetRssi string

	//GNSS定位卫星数量
	TerminalGnssCnt string
}

var (
	dbhost     string
	dbport     string
	dbuser     string
	dbpassword string
)
var sessionPool client.SessionPool

/*
 * 连接数据库
 */
func ContactDataBase(poolSize int, host string) {
	//打印数据库连接信息
	//fmt.Println("iotDB数据库Host：" + config_yaml.ReadConfid().Iotdb.Host)
	//fmt.Println("iotDB数据库Port：" + config_yaml.ReadConfid().Iotdb.Port)
	//fmt.Println("iotDB数据库User：" + config_yaml.ReadConfid().Iotdb.User)
	//fmt.Println("iotDB数据库Password：" + config_yaml.ReadConfid().Iotdb.Password)
	//连接数据库
	config := &client.PoolConfig{
		Host:     host,                //config_yaml.ReadConfid().Iotdb.Host,
		Port:     "6667",              //config_yaml.ReadConfid().Iotdb.Port,
		UserName: "vdam",              //config_yaml.ReadConfid().Iotdb.User,
		Password: "changsha20240501!", //config_yaml.ReadConfid().Iotdb.Password,
	}
	sessionPool = client.NewSessionPool(config, poolSize, 6000, 6000, false)
	//defer sessionPool.Close()
}

/*
 * 批量插入TerminalData数据List到iotDB数据库
 */
func BatchInsertDataToDB(terminalDatas *list.List) {
	ContactDataBase(100, "1.94.27.11")
	dealWhitData(terminalDatas)
}

func generateRandomMillis() int64 {
	// 设置随机种子
	rand.Seed(time.Now().UnixNano())

	// 定义时间范围
	start := time.Date(2023, time.January, 1, 0, 0, 0, 0, time.UTC)
	end := time.Date(2023, time.December, 31, 23, 59, 59, 999999000, time.UTC)

	// 转换为Unix毫秒时间戳
	startMillis := start.UnixNano() / 1e6
	endMillis := end.UnixNano() / 1e6

	// 生成随机时间戳
	delta := endMillis - startMillis
	randomMillis := startMillis + rand.Int63n(delta)

	return randomMillis
}

/*
 * 根据参数需要插入数据的数量
 * 开始时间
 * 设备号-即节点
 * 批量插入测试数据List到iotDB数据库
 */
func BatchInsertTestDataToDB(maxOneTimeDealData int, startTime int64, deviceNum string) {
	//ContactDataBase()
	session, err := sessionPool.GetSession()
	defer sessionPool.PutBack(session)
	var sqls []string
	for i := 1; i < maxOneTimeDealData+1; i++ {
		//nowtime := fmt.Sprintf("%d", startTime+int64(i))
		nowtime := generateRandomMillis()
		endSql := fmt.Sprintf(`INSERT INTO root.vadm.dps.%s (timestamp, terminal_sn, isFixed, longitude, latitude, elevation,direction, terminal_time, terminal_miles, speed, terminal_over_speed, terminal_tired_drive, terminal_gnss_error,terminal_ant_open, terminal_ant_short, terminal_under_vol, terminal_no_vol, terminal_acc_status, terminal_net_rssi,terminal_gnss_cnt) VALUES (%d, "ceshiinsert2", "0", "27.855674931274", "34.9837487474664", "taohuiqi2", "144hhusus", "2022-05-02 16:34:45", "12.1024124174", "120.1784761244", "1", "0", "1", "1", "0", "1", "0", "1", "1", "1")`,
			deviceNum, nowtime)
		sqls = append(sqls, endSql)
		//var sql = "insert into root.vadm.dps.terminal_sn_nownum (timestamp, terminal_sn, isFixed, longitude, latitude, elevation, direction, terminal_time, terminal_miles, speed, terminal_over_speed, terminal_tired_drive, terminal_gnss_error, terminal_ant_open, terminal_ant_short, terminal_under_vol, terminal_no_vol, terminal_acc_status, terminal_net_rssi, terminal_gnss_cnt) values (nowtime,\"ceshiinsert2\", \"0\", \"27.855674931274\", \"34.9837487474664\", \"taohuiqi2\", \"144hhusus\",\"2022-05-02 16:34:45\", \"12.1024124174\", \"120.1784761244\", \"1\", \"0\", \"1\", \"1\",\"0\", \"1\", \"0\", \"1\", \"1\", \"1\")"
		//var endSql = strings.ReplaceAll(sql, "nowtime", nowtime)
		//var endSql1 = strings.ReplaceAll(endSql, "nownum", deviceNum)
		//sqls = append(sqls, endSql1)
	}
	if err == nil {
		checkError(session.ExecuteBatchStatement(sqls))
		//fmt.Println("批量数据写入iotDB成功" + "===>>>设备编号为：" + deviceNum)
	} else {
		fmt.Println("批量写入错误")
	}

}

func dealWhitData(terminalDatas *list.List) {
	for i := terminalDatas.Front(); i != nil; i = i.Next() {
		dataJson, err := json.MarshalIndent(i.Value, "", "  ")
		if err != nil {
			log.Fatalf("JSON marshaling failed: %s", err)
		}
		var p TerminalData
		if dataJson != nil {
			err := json.Unmarshal([]byte(dataJson), &p)
			if err != nil {
				log.Fatalf("JSON Unmarshal error: %v", err)
			}
		}
		var (
			deviceId     = []string{"root.vadm.dps.terminal_data_unpack"}
			measurements = [][]string{{"terminal_sn", "is_fixed", "longitude", "latitude", "elevation",
				"direction", "terminal_time", "terminal_miles", "speed", "terminal_over_speed", "terminal_tired_drive",
				"terminal_gnss_error", "terminal_ant_open", "terminal_ant_short", "terminal_under_vol", "terminal_no_vol",
				"terminal_acc_status", "terminal_net_rssi", "terminal_gnss_cnt"}}
			dataTypes = [][]client.TSDataType{{client.TEXT, client.TEXT, client.TEXT, client.TEXT, client.TEXT,
				client.TEXT, client.TEXT, client.TEXT, client.TEXT, client.TEXT, client.TEXT,
				client.TEXT, client.TEXT, client.TEXT, client.TEXT, client.TEXT, client.TEXT,
				client.TEXT, client.TEXT}}
			values = [][]interface{}{{p.TerminalSn, p.IsFixed, p.Longitude, p.Latitude, p.Elevation,
				p.Direction, p.TerminalTime, p.TerminalMiles, p.Speed, p.TerminalOverSpeed, p.TerminalTiredDrive,
				p.TerminalGnssError, p.TerminalAntOpen, p.TerminalAntShort, p.TerminalUnderVol, p.TerminalNoVol,
				p.TerminalAccStatus, p.TerminalNetRssi, p.TerminalGnssCnt}}
			timestamp = []int64{time.Now().Unix()}
		)
		session, err := sessionPool.GetSession()
		defer sessionPool.PutBack(session)
		if err == nil {
			checkError(session.InsertRecords(deviceId, measurements, dataTypes, values, timestamp))
			fmt.Println("终端编号为：" + p.TerminalSn + "的数据写入iotDB成功")
		}
	}
}

/*
 * 根据起始时间删除数据(时间为int64)
 */
func DeleteData(start int64, end int64) {
	ContactDataBase(100, "1.94.27.11")
	var (
		paths     = []string{"root.vadm.dps.terminal_data_unpack.*"}
		startTime = start
		endTime   = end
	)
	session, err := sessionPool.GetSession()
	defer sessionPool.PutBack(session)
	if err == nil {
		checkError(session.DeleteData(paths, startTime, endTime))
		fmt.Println("删除<<" + paths[0] + ">>时序数据成功！")
	}
}

/*
 * 创建时序节点
 */
func SetStorageGroup(sg string) {
	ContactDataBase(100, "1.94.27.11")
	session, err := sessionPool.GetSession()
	defer sessionPool.PutBack(session)
	if err == nil {
		for i := 1; i < 10000; i++ {
			session.SetStorageGroup(sg + strconv.Itoa(i))
			fmt.Println("创建第" + strconv.Itoa(i) + "个StorageGroup时序节点成功！" + "====>>路径为：" + sg + strconv.Itoa(i))
		}
	}
}

func CreateAlignedTimeseries(prefixPath string) {
	ContactDataBase(100, "1.94.27.11")
	var (
		measurements = []string{"terminal_sn", "isFixed", "longitude", "latitude", "elevation",
			"direction", "terminal_time", "terminal_miles", "speed", "terminal_over_speed", "terminal_tired_drive",
			"terminal_gnss_error", "terminal_ant_open", "terminal_ant_short", "terminal_under_vol", "terminal_no_vol",
			"terminal_accStatus", "terminal_net_rssi", "terminal_gnss_cnt"}
		measurementAlias = []string{"terminal_sn", "is_fixed", "longitude", "latitude", "elevation",
			"direction", "terminal_time", "terminal_miles", "speed", "terminal_over_speed", "terminal_tired_drive",
			"terminal_gnss_error", "terminal_ant_open", "terminal_ant_short", "terminal_under_vol", "terminal_no_vol",
			"terminal_acc_status", "terminal_net_rssi", "terminal_gnss_cnt"}
		dataTypes = []client.TSDataType{
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
			client.TEXT,
		}
		encodings = []client.TSEncoding{
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
			client.PLAIN,
		}
		compressors = []client.TSCompressionType{
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
			client.LZ4,
		}
	)
	session, err := sessionPool.GetSession()
	defer sessionPool.PutBack(session)
	if err == nil {
		for i := 1; i < 10000; i++ {
			checkError(session.CreateAlignedTimeseries(prefixPath+strconv.Itoa(i), measurements, dataTypes, encodings, compressors, measurementAlias))
			fmt.Println("创建第" + strconv.Itoa(i) + "个Timeseries时序节点成功！" + "===>>；路径为：" + prefixPath + strconv.Itoa(i))
		}
	}

}

func checkError(status *rpc.TSStatus, err error) {
	if err != nil {
		log.Fatal(err)
	}
	if status != nil {
		if err = client.VerifySuccess(status); err != nil {
			log.Println(err)
		}
	}
}
